iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 12
0
Software Development

後端基礎PHP+Mysql & Laravel 30日養成計畫系列 第 12

Day 12 淺談物件導向(二):修飾子、建構子

  • 分享至 

  • xImage
  •  

什麼是修飾子

修飾子,在程式語言中指的是用來修飾「屬性」或「方法」的關鍵字。
又分為:

  • 靜態修飾子(static):讓屬性或方法屬於類別本身,而非物件實例
  • 存取修飾子(public, protected, private):控制元件的存取權限(誰能用)
  • 抽象與最終修飾子(abstract, final):控制類別與方法的繼承與實作行為
  • 常數與唯獨修飾子(const, readonly):控制屬性是否可變動
  • 結構性修飾子(interface、trait):

各類修飾子的詳細介紹

靜態修飾子 static

靜態修飾子 static 的特點是不須先建立物件就能直接使用,可以省下不必要的記憶體空間使用。適用於全域共用、不會因不同物件而有不同的屬性。
不過需要注意的是,static 屬性要謹慎使用。要避免把每個物件都應該不同的屬性設成 static,否則會出現個別資料被錯誤混用的問題。另外,若程式中大量依賴 static 屬性,會讓資料在多處共享,導致狀態可能被污染、難以追蹤與測試,降低程式的可維護性與彈性。

存取修飾子 public, protected, private

  • public:公有變數,需建立物件後才能使用,可在類別內部與外部被存取。由於可以被外部隨意修改或呼叫,若裡面有業務邏輯需要保護,最好不要直接設 public,而是用 getter/setter 來包裝。
  • protected:建立物件後才可使用,類別內部和繼承類別可用。
  • private:私有變數,建立物件後才可使用,且只能在類別內部中使用。
    使用範圍由大至小:static > public > protected > private。
    另外,如果系統沒有繼承結構,protected 和 private 的差異不大。

靜態修飾子和存取修飾子的使用時機以下直接舉例說明會比較好理解:
假設我們要開發一個公司的內部員工系統,會有「公司 (Company)」與「員工 (Employee)」等類別。
這些類別會包含不同屬性,例如:

  • 公司名稱、公司規定的最低薪資

  • 員工姓名、職稱、薪資等

其中,公司名稱與最低薪資標準屬於整個公司共用、不會因個別員工而改變的資料,
因此適合設為 static 屬性。

至於員工姓名、職稱、薪資等屬性則屬於每個員工個別擁有的資料,而這些屬性的「可見度」就要依照業務邏輯決定。

例如,假設要讓系統各處都能顯示員工姓名,並且員工姓名沒有相關的業務邏輯需要被保護,則可以將它設為 public。
而如果員工薪資只有在需要顯示、計算薪資的模組才會用到,則可設為 private 或 protected。例如:員工的基本薪資屬性,如果未來有「固定薪資員工」與「時薪員工」子類別要使用,可以設 protected,方便子類別計算薪資。

抽象與最終修飾子 abstract, final

  • abstract:表示類別不能被實例化,或方法必須被子類別實作。使用時機:作為模板或介面樣板時。
  • final:阻止類別被繼承,或方法被覆寫。使用時機:有核心邏輯需要被保護時。

常數與唯獨修飾子 const, readonly

  • const:定義不可變動的常數。
  • readonly:屬性只能在建構時指定一次。使用時機:適合不應被修改的資料,例如 id, createdAt 等

const 和 readonly 最大的差別在於:const 是 static 屬性,他不屬於任何物件,無法在 runtime 改變;而 readonly 則屬於實例屬性,能夠在建構子中設定一次,設定之後就不能再修改。

結構性修飾子 interface, trait

  • interface:定義介面,規範子類別行為
  • trait:在 PHP 中提供水平共用程式碼的方法(多重繼承的替代)

建構子/解構

建構子(__construct())是當物件「出生」時自動執行的初始化動作。
常見用途:
* 設定初始屬性值
* 檢查參數是否合法
* 進行依賴注入
* 建立資料庫連線或開啟檔案等初始化動作

解構子(__destruct()) 則是當物件不再被使用(例如程式結束或變數被釋放)時,系統會自動呼叫的方法。
常見用途:

  • 關閉資料庫連線
  • 釋放檔案、資源、記憶體
  • 寫入 log、記錄清理動作

範例程式碼

<?php

class Company
{
    // 公司名稱不會因不同員工而有不同,因此設為 static 屬性
    public static string $name = 'TechNova Inc.';
    
    /* 
      公司統一規定的最低薪資標準(全員共用,不隨個別員工變動)
      因此設為 static 屬性以便整個系統共用與存取
    */
    public static int $minimumSalary = 30000;
}

class Employee
{
    public string $name;
    public string $position;
    
    // 私有屬性,避免外部直接改動
    private int $salary;

    // 建構子
    public function __construct(string $name, string $position, int $salary)
    {
        $this->name = $name;
        $this->position = $position;
        $this->setSalary($salary);
    }
    
    // 解構子:物件銷毀時自動執行
    public function __destruct()
    {
        echo "員工 {$this->name} 離開系統。\n";
    }

    // 使用 private 封裝邏輯
    private function setSalary(int $salary)
    {
        // 若薪資低於公司規定的最低薪資,則自動調整
        $this->salary = max($salary, Company::$minimumSalary);
    }

    // Public 方法讓外部查詢薪水
    public function getSalary(): int
    {
        return $this->salary;
    }

    // 靜態方法:顯示公司資訊(可不依賴員工物件)
    public static function companyInfo(): void
    {
        echo "Company: " . Company::$name . PHP_EOL;
        echo "Minimum Salary: " . Company::$minimumSalary . PHP_EOL;
    }
}

// === 測試 ===
Employee::companyInfo();

$john = new Employee('John', 'Backend Engineer', 28000);
$jane = new Employee('Jane', 'Team Lead', 55000);

echo $john->name . ' salary: ' . $john->getSalary() . PHP_EOL;
echo $jane->name . ' salary: ' . $jane->getSalary() . PHP_EOL;

unset($emp); // 手動銷毀物件,呼叫解構子

上一篇
Day 11 淺談物件導向 (一):方法與類別
下一篇
Day 13 物件導向三大概念:封裝、繼承、多型
系列文
後端基礎PHP+Mysql & Laravel 30日養成計畫35
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言